package front_chat_api

import (
	"blog_go/models/ctype"
	"blog_go/utils"
	"encoding/json"
	"fmt"
	"github.com/DanPlayer/randomname"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"github.com/sirupsen/logrus"
	"net/http"
	"strings"
	"sync"
	"time"
)

type ChatUser struct {
	Conn     *Connection
	NickName string `json:"nick_name"`
	Avatar   string `json:"avatar"`
}

// 线程不安全 暂时用一下
var connMap = map[string]*ChatUser{}
var mutex sync.Mutex

type ChatGroupReq struct {
	Content string        `json:"content"`  // 聊天的内容
	MsgType ctype.MsgType `json:"msg_type"` // 聊天类型
}
type ChatGroupRsp struct {
	NickName string `json:"nick_name"` // 前端自己生成
	Avatar   string `json:"avatar"`    // 头像
	// 下面的数据是变动的
	MsgType     ctype.MsgType `json:"msg_type"`     // 聊天类型
	Content     string        `json:"content"`      // 聊天的内容
	OnlineCount int           `json:"online_count"` // 在线人数
	Date        time.Time     `json:"created_at"`   // 消息的时间
}

// chat不指定大小为0 会一直阻塞
//var connChan = make(chan *Connection, 100)
//var syncMap sync.Map

func (ChatApi) ChatGroup(c *gin.Context) {
	value, exists := c.Get(utils.Claims)
	var claims *utils.CustomClaims
	if exists {
		claims = value.(*utils.CustomClaims)
	}
	var (
		// websocket 长连接
		wsConn  *websocket.Conn
		err     error
		conn    *Connection
		data    []byte
		upgrade = websocket.Upgrader{
			//允许跨域
			CheckOrigin: func(r *http.Request) bool {
				return true
			},
		}
		req  ChatGroupReq
		rsp  ChatGroupRsp
		user ChatUser
	)
	// header中添加Upgrade:websocket
	if wsConn, err = upgrade.Upgrade(c.Writer, c.Request, nil); err != nil {
		return
	}
	if conn, err = InitConnection(wsConn); err != nil {
		goto ERR
	}
	// 组装conn的map
	user.Conn = conn
	if exists {
		user.NickName = claims.NickName
		user.Avatar = claims.Avatar
	} else {
		nickName := randomname.GenerateName()
		nickNameFirst := string([]rune(nickName)[0])
		avatar := fmt.Sprintf("uploads/chat_avatar/%s.png", nickNameFirst)
		user.NickName = nickName
		user.Avatar = avatar
	}
	connMapAdd(conn, user)
	// 心跳检测
	//go func() {
	//	for {
	//		if err := conn.WriteMessage([]byte("heartbeat")); err != nil {
	//			return
	//		}
	//		time.Sleep(time.Second * 1)
	//	}
	//}()
	// 设置回复昵称
	rsp.NickName = user.NickName
	rsp.Avatar = user.Avatar
	for {
		// 读取消息
		if data, err = conn.ReadMessage(); err != nil {
			goto ERR
		}
		if err = json.Unmarshal(data, &req); err != nil {
			logrus.Error(err)
			continue
		}
		rsp.MsgType = req.MsgType
		rsp.Date = time.Now()
		rsp.OnlineCount = len(connMap)
		switch req.MsgType {
		case ctype.InRoomMsg:
			rsp.Content = rsp.NickName + ",欢迎您进入聊天室~~~"
		case ctype.TextMsg:
			if strings.TrimSpace(req.Content) == "" {
				continue
			}
			rsp.Content = req.Content
		case ctype.ImageMsg:
		case ctype.VoiceMsg:
		case ctype.VideoMsg:
		case ctype.SystemMsg:
		case ctype.OutRoomMsg:
			rsp.Content = rsp.NickName + ",已退出聊天室~~~"
			goto ERR
		default:
			// 这个消息是发给自己的
			rsp.MsgType = ctype.Other
			rsp.Content = "消息类型错误"
			marshal, _ := json.Marshal(rsp)
			// 保存到数据库
			conn.SaveDBChat(rsp)
			if err = conn.WriteMessage(marshal); err != nil {
				goto ERR
			}
			continue
		}
		// 奖读取到的消息发送给出自己外的所有连接
		conn.SaveDBChat(rsp)
		sendOtherAllUser(rsp, conn, err)
	}
ERR:
	connMapDel(conn)
	conn.Close()
}

func connMapDel(conn *Connection) {
	mutex.Lock()
	delete(connMap, conn.id)
	mutex.Unlock()
}

func connMapAdd(conn *Connection, user ChatUser) {
	mutex.Lock()
	connMap[conn.id] = &user
	mutex.Unlock()
}

func sendOtherAllUser(rsp ChatGroupRsp, conn *Connection, err error) {
	marshal, _ := json.Marshal(rsp)
	for id, user := range connMap {
		if id != conn.id {
			if err = user.Conn.WriteMessage(marshal); err != nil {
				continue
			}
		}
	}
}
